%% Multiplying two matrices element by element does not need broadcasting ==============================
A = randn(100, 100);
B = randn(100, 100);
res = A.*B % notice entrywise ".*" instead of matrix "*"

%% Multiplying each column of a matrix by a different scalar does ====================
clc
A = randn(1000, 1000);
x = randn(1000, 1);

t = tic;
res = A.*x;
toc(t)

t = tic;
res = A*diag(x);
toc(t)

% Remember Matlab uses JIT (just in time compilation).
% Thus, to compare computation time, put the code
% in a file, and save; run the code once and ignore
% timings for that run (code was compiled); run it again.


%% Creating matrix of every sums of every pair ===============================================================
clc
A = randn(1000, 1);
B = randn(1, 1000);

% using built-in function
t = tic;
C = A + B;
toc(t)

% is more efficient than loops
t = tic;
C = zeros(1000, 1000);
for i = 1:1000
    for j = 1:1000
        C(i,j) = A(i) + B(j);
    end
end
toc(t)


%% Normalizing each column of a matrix ======================
clc
A = randn(1000, 1000);
% fast way
tic
B = A ./ sum(A, 1);
toc
% slow way
tic
B = zeros(size(A));
for i = 1:size(A, 2)
    B(:, i) = A(:, i) / sum(A(:, i));
end
toc

%% applying a function to a grid =============================
clc

[X, Y] = meshgrid(linspace(-5, 5, 1000), linspace(-5, 5, 2000));
f = @(x, y) sin(sqrt(x.^2 + y.^2)) ./ sqrt(x.^2 + y.^2);

% Broadcasting approach
tic
Z_broadcast = f(X, Y);
toc

% Naive approach (using loops)
Z_loops = zeros(size(X));

tic
for i = 1:size(X, 1)
    for j = 1:size(X, 2)
        Z_loops(i, j) = f(X(i, j), Y(i, j));
    end
end
toc

